﻿using HslCommunication.BasicFramework;
using HslCommunication.ModBus;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Net;
using System.Runtime.ConstrainedExecution;
using System.Text;
using System.Threading.Tasks;
using Tools.Enum;

namespace AutoControlSpectrum.Manufacturer
{
    internal class ModbusServer
    {
        private static readonly ModbusServer instance = new ModbusServer();

        /// <summary>
        /// 私有构造函数，防止实例化
        /// </summary>
        private ModbusServer()
        { }

        /// <summary>
        ///  公共静态方法，返回唯一的实例
        /// </summary>
        internal static ModbusServer Instance => instance;

        /// <summary>
        /// 消息回调
        /// </summary>
        public Action<LogTypeEnum, string> MsgCallback = (a, b) => { };

        /// <summary>
        /// 日志记录器
        /// </summary>
        private ILogger _logger { get; set; }

        /// <summary>
        /// Modbus服务
        /// </summary>
        private ModbusTcpServer busTcpServer;

        /// <summary>
        /// 服务启动端口
        /// </summary>
        private const int PROT = 502;

        /// <summary>
        /// 启动服务
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="MsgCallback">消息回调</param>
        internal void Start(ILogger logger, Action<LogTypeEnum, string> MsgCallback)
        {
            if (busTcpServer != null)
            {
                MsgCallback(LogTypeEnum.Msg, "服务已经启动，如需重启请先停止！");
                return;
            }
            this.MsgCallback = MsgCallback;
            this._logger = logger ?? throw new Exception("请提供日志记录器");

            busTcpServer = new ModbusTcpServer();
            busTcpServer.DataFormat = HslCommunication.Core.DataFormat.CDAB;
            busTcpServer.LogNet = new HslCommunication.LogNet.LogNetSingle("logs.txt");
            busTcpServer.LogNet.BeforeSaveToFile += LogNet_BeforeSaveToFile;
            //busTcpServer.OnDataReceived += BusTcpServer_OnDataReceived;
            busTcpServer.ServerStart(PROT);

            // 启动测试
            ModBusMonitorAddress startMonitorAddress = new ModBusMonitorAddress();
            startMonitorAddress.Address = ushort.Parse("20"); // 监听地址
            startMonitorAddress.OnWrite += StartMonitorAddress_OnWrite;
            busTcpServer.AddSubcription(startMonitorAddress);

            MsgCallback(LogTypeEnum.Msg, $"ModbusServer服务已启动，端口：{PROT}");
        }

        /// <summary>
        /// 监听启动测试
        /// </summary>
        /// <param name="monitor"></param>
        /// <param name="value"></param>
        private void StartMonitorAddress_OnWrite(ModBusMonitorAddress monitor, short value)
        {
            var start = busTcpServer.ReadInt16("20").Content;
            if (start == 1)
            {
                var sampleNo = busTcpServer.ReadString("10", 10).Content.Trim('\0');
                if (string.IsNullOrWhiteSpace(sampleNo))
                {
                    MsgCallback(LogTypeEnum.Msg, $"监听到启动信号，但样品条码为空，请联系自动化");
                    return;
                }
                if (DeviceControl.Instance.IsExistSample)
                {
                    MsgCallback(LogTypeEnum.Msg, DateTime.Now.ToString("[HH:mm:ss] ") + string.Format("[上一个样品还没有结束] {0}", Environment.NewLine));
                    return;
                }
                var jieShu = busTcpServer.ReadInt16("21").Content;
                if (jieShu == 1)
                {
                    MsgCallback(LogTypeEnum.Msg, DateTime.Now.ToString("[HH:mm:ss] ") + string.Format("[上一次检测的结果并没有读取，无法开始新的检测] {0}", Environment.NewLine));
                    return;
                }

                MsgCallback(LogTypeEnum.Data, $"{sampleNo.Trim('\0')}");

                busTcpServer.Write("20", (short)0);
                Clear(10, 19);
                Clear(20, 21);
            }
        }

        /// <summary>
        /// 当有日志记录的时候，触发，将日志信息也在主界面进行输出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LogNet_BeforeSaveToFile(object sender, HslCommunication.LogNet.HslEventArgs e)
        {
            string msg = e.HslMessage.ToString() + Environment.NewLine;
            if (msg.Contains("下线") || msg.Contains("上线"))
            {
                MsgCallback(LogTypeEnum.Msg, msg);
            }
        }

        /// <summary>
        /// 关闭服务
        /// </summary>
        internal void Dispose()
        {
            busTcpServer?.ServerClose();
            busTcpServer?.Dispose();
            busTcpServer = null;
        }

        /// <summary>
        /// 发送检测结果
        /// </summary>
        /// <param name="sampleNo">样品编号</param>
        /// <param name="cppma">氧</param>
        /// <param name="oppma">碳</param>
        internal void SendSampleData(string sampleNo, float cppma, float oppma)
        {
            // 先清空
            busTcpServer.Write("22", (short)0);
            busTcpServer.Write("24", (short)0);
            Clear(26, 34);

            // 在赋值
            busTcpServer.Write("21", (short)1);
            busTcpServer.Write("22", cppma);
            busTcpServer.Write("24", oppma);
            busTcpServer.Write("26", sampleNo);
        }

        /// <summary>
        /// 清空寄存器
        /// </summary>
        /// <param name="begin">寄存器的起始位置</param>
        /// <param name="end">清除寄存器的个数</param>
        private void Clear(int begin, int end)
        {
            // 清空寄存器范围，设置为0
            for (int i = 0; i < end; i++)
            {
                busTcpServer.Write((begin + i).ToString(), 0x00);
            }
        }
    }
}